#include "symbol.h"

#include <QFontMetrics>
#include <QPolygonF>

namespace SymbolEditor
{
    Item::Item():
        m_lineStyle(SolidLine),
        m_lineWidth(MediumLine),
        m_lineColor(SecondaryContent),
        m_fillStyle(SolidFill),
        m_fillColor(BackgroundHighlight),
        m_opacity(100),
        m_position(QPointF(0.0, 0.0)),
        m_rotation(0.0),
        m_locked(false),
        m_visible(true),
        m_xMirrored(false),
        m_yMirrored(false)
    {

    }

    Item::~Item()
    {

    }

    QString Item::friendlyPropertyName(quint64 id) const
    {
        switch (id)
        {
            case PositionProperty:
                return "Position";
            case OpacityProperty:
                return "Opacity";
            case RotationProperty:
                return "Rotation";
            case LockedProperty:
                return "Locked";
            case VisibilityProperty:
                return "Visibility";
            case XMirroredProperty:
                return "X Mirroring";
            case YMirroredProperty:
                return "Y Mirroring";
            case LineStyleProperty:
                return "Line style";
            case LineWidthProperty:
                return "Line width";
            case LineColorProperty:
                return "Line Color";
            case FillStyleProperty:
                return "Fill style";
            case FillColorProperty:
                return "Fill color";
            default:
                return "Unknown";
        }
    }

    QVariant Item::property(quint64 id) const
    {
        switch (id)
        {
            case PositionProperty:
                return m_position;
            case OpacityProperty:
                return m_opacity;
            case RotationProperty:
                return m_rotation;
            case LockedProperty:
                return m_locked;
            case VisibilityProperty:
                return m_visible;
            case XMirroredProperty:
                return m_xMirrored;
            case YMirroredProperty:
                return m_yMirrored;
            case LineStyleProperty:
                return QVariant::fromValue(m_lineStyle);
            case LineWidthProperty:
                return QVariant::fromValue(m_lineWidth);
            case LineColorProperty:
                return QVariant::fromValue(m_lineColor);
            case FillStyleProperty:
                return QVariant::fromValue(m_fillStyle);
            case FillColorProperty:
                return QVariant::fromValue(m_fillColor);
            default:
                return QVariant();
        }
    }

    void Item::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            case PositionProperty:
                m_position = value.toPointF();
                break;
            case OpacityProperty:
                m_opacity = value.toReal();
                break;
            case RotationProperty:
                m_rotation = value.toReal();
                break;
            case LockedProperty:
                m_locked = value.toBool();
                break;
            case VisibilityProperty:
                m_visible = value.toBool();
                break;
            case XMirroredProperty:
                m_xMirrored = value.toBool();
                break;
            case YMirroredProperty:
                m_yMirrored = value.toBool();
                break;
            case LineStyleProperty:
                Q_ASSERT(value.canConvert<LineStyle>());
                m_lineStyle = value.value<LineStyle>();
                break;
            case LineWidthProperty:
                Q_ASSERT(value.canConvert<LineWidth>());
                m_lineWidth = value.value<LineWidth>();
                break;
            case LineColorProperty:
                Q_ASSERT(value.canConvert<Color>());
                m_lineColor = value.value<Color>();
                break;
            case FillStyleProperty:
                Q_ASSERT(value.canConvert<FillStyle>());
                m_fillStyle = value.value<FillStyle>();
                break;
            case FillColorProperty:
                Q_ASSERT(value.canConvert<Color>());
                m_fillColor = value.value<Color>();
                break;
            default:
                break;
        }
    }

    QList<PropertyId> Item::propertyIdList() const
    {
        QList<PropertyId> result;
        result << PositionProperty
               << OpacityProperty
               << RotationProperty
               << LockedProperty
               << VisibilityProperty
               << XMirroredProperty
               << YMirroredProperty
               << LineStyleProperty
               << LineWidthProperty
               << LineColorProperty
               << FillStyleProperty
               << FillColorProperty;
        return result;
    }

    quint64 Item::id() const
    {
        return m_id;
    }

    void Item::setId(quint64 id)
    {
        m_id = id;
    }

    void Item::setPosition(const QPointF &pos)
    {
        m_position = pos;
    }

    QPointF Item::position() const
    {
        return m_position;
    }

    void Item::setOpacity(qreal opacity)
    {
        m_opacity = opacity;
    }

    qreal Item::opacity() const
    {
        return m_opacity;
    }

    void Item::setRotation(qreal rotation)
    {
        m_rotation = rotation;
    }

    qreal Item::rotation() const
    {
        return m_rotation;
    }

    void Item::setLocked(bool locked)
    {
        m_locked = locked;
    }

    bool Item::isLocked() const
    {
        return m_locked;
    }

    void Item::setVisible(bool visible)
    {
        m_visible = visible;
    }

    bool Item::isVisible() const
    {
        return m_visible;
    }

    void Item::setXMirrored(bool mirrored)
    {
        m_xMirrored = mirrored;
    }

    bool Item::isXMirrored() const
    {
        return m_xMirrored;
    }

    void Item::setYMirrored(bool mirrored)
    {
        m_yMirrored = mirrored;
    }

    bool Item::isYMirrored() const
    {
        return m_yMirrored;
    }

    void Item::setLineStyle(LineStyle style)
    {
        m_lineStyle = style;
    }

    LineStyle Item::lineStyle() const
    {
        return m_lineStyle;
    }

    void Item::setLineWidth(LineWidth width)
    {
        m_lineWidth = width;
    }

    LineWidth Item::lineWidth() const
    {
        return m_lineWidth;
    }

    void Item::setLineColor(Color color)
    {
        m_lineColor = color;
    }

    Color Item::lineColor() const
    {
        return m_lineColor;
    }

    void Item::setFillStyle(FillStyle style)
    {
        m_fillStyle = style;
    }

    FillStyle Item::fillStyle() const
    {
        return m_fillStyle;
    }

    void Item::setFillColor(Color color)
    {
        m_fillColor = color;
    }

    Color Item::fillColor() const
    {
        return m_fillColor;
    }

    Symbol::Symbol()
    {

    }

    Symbol::~Symbol()
    {
        //qDeleteAll(drawingItems); // We don't have ownership
    }

    RectangleItem::RectangleItem():
        m_width(0.0),
        m_height(0.0)
    {

    }

    RectangleItem::~RectangleItem()
    {

    }

    qreal RectangleItem::width() const
    {
        return m_width;
    }

    void RectangleItem::setWidth(qreal width)
    {
        m_width = width;
    }

    qreal RectangleItem::height() const
    {
        return m_height;
    }

    void RectangleItem::setHeight(qreal height)
    {
        m_height = height;
    }

    ItemType RectangleItem::type() const
    {
        return Rectangle;
    }

    Item *RectangleItem::clone() const
    {
        auto item = new RectangleItem;
        *item = *this;
        return item;
    }

    QPainterPath RectangleItem::outline() const
    {
        QPainterPath path;
        path.addRect(0, 0, m_width, m_height);
        return path;
    }

    QString RectangleItem::friendlyTypeName() const
    {
        return "Rectangle";
    }

    QString RectangleItem::friendlyPropertyName(quint64 id) const
    {
        switch (id)
        {
            case PositionProperty:
                return "Top left";
            case WidthProperty:
                return "Width";
            case HeightProperty:
                return "Height";
            default:
                return Item::friendlyPropertyName(id);
        }
    }

    QIcon RectangleItem::icon() const
    {
        return QIcon::fromTheme("draw-rectangle");
    }

    QVariant RectangleItem::property(quint64 id) const
    {
        switch (id)
        {
            case WidthProperty:
                return m_width;
            case HeightProperty:
                return m_height;
            default:
                return Item::property(id);
        }
    }

    void RectangleItem::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            case WidthProperty:
                m_width = value.toReal();
                break;
            case HeightProperty:
                m_height = value.toReal();
                break;
            default:
                Item::setProperty(id, value);
                break;
        }
    }

    QList<PropertyId> RectangleItem::propertyIdList() const
    {
        return Item::propertyIdList()
                << WidthProperty
                << HeightProperty;
    }

    CircleItem::CircleItem():
        Item(),
        m_radius(0.0)
    {

    }

    CircleItem::~CircleItem()
    {

    }

    qreal CircleItem::radius() const
    {
        return m_radius;
    }

    void CircleItem::setRadius(qreal radius)
    {
        m_radius = radius;
    }

    ItemType CircleItem::type() const
    {
        return Circle;
    }

    Item *CircleItem::clone() const
    {
        auto item = new CircleItem;
        *item = *this;
        return item;
    }

    QPainterPath CircleItem::outline() const
    {
        QPainterPath path;
        path.addEllipse(QPointF(0, 0), m_radius, m_radius);
        return path;
    }

    QString CircleItem::friendlyTypeName() const
    {
        return "Circle";
    }

    QString CircleItem::friendlyPropertyName(quint64 id) const
    {
        switch (id)
        {
            case PositionProperty:
                return "Center";
            case RadiusProperty:
                return "Radius";
            default:
                return Item::friendlyPropertyName(id);
        }
    }

    QIcon CircleItem::icon() const
    {
        return QIcon::fromTheme("draw-circle");
    }

    QVariant CircleItem::property(quint64 id) const
    {
        switch (id)
        {
            case RadiusProperty:
                return m_radius;
            default:
                return Item::property(id);
        }
    }

    void CircleItem::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            case RadiusProperty:
                m_radius = value.toReal();
                break;
            default:
                Item::setProperty(id, value);
                break;
        }
    }

    QList<PropertyId> CircleItem::propertyIdList() const
    {
        return Item::propertyIdList()
                << RadiusProperty;
    }

    CircularArcItem::CircularArcItem():
        Item(),
        m_radius(0.0),
        m_startAngle(0.0),
        m_spanAngle(360.0)
    {

    }

    CircularArcItem::~CircularArcItem()
    {

    }

    qreal CircularArcItem::radius() const
    {
        return m_radius;
    }

    void CircularArcItem::setRadius(qreal radius)
    {
        m_radius = radius;
    }

    qreal CircularArcItem::startAngle() const
    {
        return m_startAngle;
    }

    void CircularArcItem::setStartAngle(qreal angle)
    {
        m_startAngle = angle;
    }

    qreal CircularArcItem::spanAngle() const
    {
        return m_spanAngle;
    }

    void CircularArcItem::setSpanAngle(qreal angle)
    {
        m_spanAngle = angle;
    }

    ItemType CircularArcItem::type() const
    {
        return CircularArc;
    }

    Item *CircularArcItem::clone() const
    {
        auto item = new CircularArcItem;
        *item = *this;
        return item;
    }

    QPainterPath CircularArcItem::outline() const
    {
        QPainterPath path;
        if (qFuzzyCompare(m_spanAngle, 360))
        {
            path.addEllipse(-m_radius, -m_radius, 2*m_radius, 2*m_radius);
        }
        else
        {
            path.arcTo(-m_radius, -m_radius, 2*m_radius, 2*m_radius, m_startAngle, m_spanAngle);
            path.closeSubpath();
        }
        return path;
    }

    QString CircularArcItem::friendlyTypeName() const
    {
        return "Circular Arc";
    }

    QString CircularArcItem::friendlyPropertyName(quint64 id) const
    {
        switch (id)
        {
            case PositionProperty:
                return "Center";
            case RadiusProperty:
                return "Radius";
            case StartAngleProperty:
                return "Start angle";
            case SpanAngleProperty:
                return "Span angle";
            default:
                return Item::friendlyPropertyName(id);
        }
    }

    QIcon CircularArcItem::icon() const
    {
        return QIcon::fromTheme("draw-halfcircle3");
    }

    QVariant CircularArcItem::property(quint64 id) const
    {
        switch (id)
        {
            case RadiusProperty:
                return m_radius;
            case StartAngleProperty:
                return m_startAngle;
            case SpanAngleProperty:
                return m_spanAngle;
            default:
                return Item::property(id);
        }
    }

    void CircularArcItem::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            case RadiusProperty:
                m_radius = value.toReal();
                break;
            case StartAngleProperty:
                m_startAngle = value.toReal();
                break;
            case SpanAngleProperty:
                m_spanAngle = value.toReal();
                break;
            default:
                Item::setProperty(id, value);
                break;
        }
    }

    QList<PropertyId> CircularArcItem::propertyIdList() const
    {
        return Item::propertyIdList()
                << RadiusProperty
                << StartAngleProperty
                << SpanAngleProperty;
    }

    EllipseItem::EllipseItem():
        Item(),
        m_xRadius(0.0),
        m_yRadius(0.0)
    {

    }

    EllipseItem::~EllipseItem()
    {

    }

    qreal EllipseItem::xRadius() const
    {
        return m_xRadius;
    }

    void EllipseItem::setXRadius(qreal radius)
    {
        m_xRadius = radius;
    }

    qreal EllipseItem::yRadius() const
    {
        return m_yRadius;
    }

    void EllipseItem::setYRadius(qreal radius)
    {
        m_yRadius = radius;
    }

    ItemType EllipseItem::type() const
    {
        return Ellipse;
    }

    Item *EllipseItem::clone() const
    {
        auto item = new EllipseItem;
        *item = *this;
        return item;
    }

    QPainterPath EllipseItem::outline() const
    {
        QPainterPath path;
        path.addEllipse(QPointF(0, 0), m_xRadius, m_yRadius);
        return path;
    }

    QString EllipseItem::friendlyTypeName() const
    {
        return "Ellipse";
    }

    QString EllipseItem::friendlyPropertyName(quint64 id) const
    {
        switch (id)
        {
            case PositionProperty:
                return "Center";
            case XRadiusProperty:
                return "X Radius";
            case YRadiusProperty:
                return "Y Radius";
            default:
                return Item::friendlyPropertyName(id);
        }
    }

    QIcon EllipseItem::icon() const
    {
        return QIcon::fromTheme("draw-ellipse");
    }

    QVariant EllipseItem::property(quint64 id) const
    {
        switch (id)
        {
            case XRadiusProperty:
                return m_xRadius;
            case YRadiusProperty:
                return m_yRadius;
            default:
                return Item::property(id);
        }
    }

    void EllipseItem::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            case XRadiusProperty:
                m_xRadius = value.toReal();
                break;
            case YRadiusProperty:
                m_yRadius = value.toReal();
                break;
            default:
                Item::setProperty(id, value);
                break;
        }
    }

    QList<PropertyId> EllipseItem::propertyIdList() const
    {
        return Item::propertyIdList()
                << XRadiusProperty
                << YRadiusProperty;
    }

    EllipticalArcItem::EllipticalArcItem():
        Item(),
        m_xRadius(0.0),
        m_yRadius(0.0),
        m_startAngle(0.0),
        m_spanAngle(360.0)
    {

    }

    EllipticalArcItem::~EllipticalArcItem()
    {

    }

    qreal EllipticalArcItem::xRadius() const
    {
        return m_xRadius;
    }

    void EllipticalArcItem::setXRadius(qreal radius)
    {
        m_xRadius = radius;
    }

    qreal EllipticalArcItem::yRadius() const
    {
        return m_yRadius;
    }

    void EllipticalArcItem::setYRadius(qreal radius)
    {
        m_yRadius = radius;
    }

    qreal EllipticalArcItem::startAngle() const
    {
        return  m_startAngle;
    }

    void EllipticalArcItem::setStartAngle(qreal angle)
    {
        m_startAngle = angle;
    }

    qreal EllipticalArcItem::spanAngle() const
    {
        return m_spanAngle;
    }

    void EllipticalArcItem::setSpanAngle(qreal angle)
    {
        m_spanAngle = angle;
    }

    ItemType EllipticalArcItem::type() const
    {
        return EllipticalArc;
    }

    Item *EllipticalArcItem::clone() const
    {
        auto item = new EllipticalArcItem;
        *item = *this;
        return item;
    }

    QPainterPath EllipticalArcItem::outline() const
    {
        QPainterPath path;
        if (qFuzzyCompare(m_spanAngle, 360))
        {
            path.addEllipse(-m_xRadius, -m_yRadius, 2*m_xRadius, 2*m_yRadius);
        }
        else
        {
            path.arcTo(-m_xRadius, -m_yRadius, 2*m_xRadius, 2*m_yRadius, m_startAngle, m_spanAngle);
            path.closeSubpath();
        }
        return path;
    }

    QString EllipticalArcItem::friendlyTypeName() const
    {
        return "Elliptical arc";
    }

    QString EllipticalArcItem::friendlyPropertyName(quint64 id) const
    {
        switch (id)
        {
            case PositionProperty:
                return "Center";
            case XRadiusProperty:
                return "X Radius";
            case YRadiusProperty:
                return "Y Radius";
            case StartAngleProperty:
                return "Start angle";
            case SpanAngleProperty:
                return "Span angle";
            default:
                return Item::friendlyPropertyName(id);
        }
    }

    QIcon EllipticalArcItem::icon() const
    {
        return QIcon::fromTheme("draw-halfcircle3");
    }

    QVariant EllipticalArcItem::property(quint64 id) const
    {
        switch (id)
        {
            case XRadiusProperty:
                return m_xRadius;
            case YRadiusProperty:
                return m_yRadius;
            case StartAngleProperty:
                return m_startAngle;
            case SpanAngleProperty:
                return m_spanAngle;
            default:
                return Item::property(id);
        }
    }

    void EllipticalArcItem::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            case XRadiusProperty:
                m_xRadius = value.toReal();
                break;
            case YRadiusProperty:
                m_yRadius = value.toReal();
                break;
            case StartAngleProperty:
                m_startAngle = value.toReal();
                break;
            case SpanAngleProperty:
                m_spanAngle = value.toReal();
                break;
            default:
                Item::setProperty(id, value);
                break;
        }
    }

    QList<PropertyId> EllipticalArcItem::propertyIdList() const
    {
        return Item::propertyIdList()
                << XRadiusProperty
                << YRadiusProperty
                << StartAngleProperty
                << SpanAngleProperty;
    }

    PolylineItem::PolylineItem():
        Item()
    {

    }

    PolylineItem::~PolylineItem()
    {

    }

    QList<QPointF> PolylineItem::vertices() const
    {
        return m_vertices;
    }

    void PolylineItem::setVertices(const QList<QPointF> &vertices)
    {
        m_vertices = vertices;
    }

    ItemType PolylineItem::type() const
    {
        return Polyline;
    }

    Item *PolylineItem::clone() const
    {
        auto item = new PolylineItem;
        *item = *this;
        return item;
    }

    QPainterPath PolylineItem::outline() const
    {
        QPainterPath path;
        path.addPolygon(QPolygonF(m_vertices.toVector()));
        path.closeSubpath();
        return path;
    }

    QString PolylineItem::friendlyTypeName() const
    {
        return "Polyline";
    }

    QString PolylineItem::friendlyPropertyName(quint64 id) const
    {
        switch (id)
        {
            case VerticesProperty:
                return "Vertices";
            default:
                return Item::friendlyPropertyName(id);
        }
    }

    QIcon PolylineItem::icon() const
    {
        return QIcon::fromTheme("draw-line");
    }

    QVariant PolylineItem::property(quint64 id) const
    {
        switch (id)
        {
            case VerticesProperty:
                return QVariant::fromValue(m_vertices);
            default:
                return Item::property(id);
        }
    }

    void PolylineItem::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            case VerticesProperty:
            {
                m_vertices = value.value<QList<QPointF>>();
                break;
            }
            default:
                Item::setProperty(id, value);
                break;
        }
    }

    QList<PropertyId> PolylineItem::propertyIdList() const
    {
        return Item::propertyIdList()
                << VerticesProperty;
    }

    PolygonItem::PolygonItem():
        Item()
    {

    }

    PolygonItem::~PolygonItem()
    {

    }

    QList<QPointF> PolygonItem::vertices() const
    {
        return m_vertices;
    }

    void PolygonItem::setVertices(const QList<QPointF> &vertices)
    {
        m_vertices = vertices;
    }

    ItemType PolygonItem::type() const
    {
        return Polygon;
    }

    Item *PolygonItem::clone() const
    {
        auto item = new PolygonItem;
        *item = *this;
        return item;
    }

    QPainterPath PolygonItem::outline() const
    {
        QPainterPath path;
        path.addPolygon(QPolygonF(m_vertices.toVector()));
        return path;
    }

    QString PolygonItem::friendlyTypeName() const
    {
        return "Polygon";
    }

    QString PolygonItem::friendlyPropertyName(quint64 id) const
    {
        switch (id)
        {
            case VerticesProperty:
                return "Vertices";
            default:
                return Item::friendlyPropertyName(id);
        }
    }

    QIcon PolygonItem::icon() const
    {
        return QIcon::fromTheme("draw-polygon");
    }

    QVariant PolygonItem::property(quint64 id) const
    {
        switch (id)
        {
            case VerticesProperty:
                return QVariant::fromValue(m_vertices);
            default:
                return Item::property(id);
        }
    }

    void PolygonItem::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            case VerticesProperty:
            {
                m_vertices = value.value<QList<QPointF>>();
                break;
            }
            default:
                Item::setProperty(id, value);
                break;
        }
    }

    QList<PropertyId> PolygonItem::propertyIdList() const
    {
        return Item::propertyIdList()
                << VerticesProperty;
    }

    LabelItem::LabelItem():
        Item(),
        m_text(""),
        m_textColor("#000000"), // FIXME
        m_fontFamily(""), // FIXME
        m_fontSize(12) // FIXME
    {

    }

    LabelItem::~LabelItem()
    {

    }

    QString LabelItem::text() const
    {
        return m_text;
    }

    void LabelItem::setText(const QString &text)
    {
        m_text = text;
    }

    QString LabelItem::textColor() const
    {
        return m_textColor;
    }

    void LabelItem::setTextColor(const QString &color)
    {
        m_textColor = color;
    }

    QString LabelItem::fontFamily() const
    {
        return m_fontFamily;
    }

    void LabelItem::setFontFamily(const QString &family)
    {
        m_fontFamily = family;
    }

    int LabelItem::fontSize() const
    {
        return m_fontSize;
    }

    void LabelItem::setFontSize(int size)
    {
        m_fontSize = size;
    }

    ItemType LabelItem::type() const
    {
        return Label;
    }

    Item *LabelItem::clone() const
    {
        auto item = new LabelItem;
        *item = *this;
        return item;
    }

    QPainterPath LabelItem::outline() const
    {
        QPainterPath path;
        QFontMetrics metrics(QFont(m_fontFamily, m_fontSize));
        path.addRect(metrics.boundingRect(m_text));
        return path;
    }

    QString LabelItem::friendlyTypeName() const
    {
        return "Label";
    }

    QString LabelItem::friendlyPropertyName(quint64 id) const
    {
        switch (id)
        {
            case FontFamilyProperty:
                return "Font family";
            case FontSizeProperty:
                return "Font size";
            case TextProperty:
                return "Text";
            case TextColorProperty:
                return "Text color";
            default:
                return Item::friendlyPropertyName(id);
        }
    }

    QIcon LabelItem::icon() const
    {
        return QIcon::fromTheme("insert-text");
    }

    QVariant LabelItem::property(quint64 id) const
    {
        switch (id)
        {
            case FontFamilyProperty:
                return m_fontFamily;
            case FontSizeProperty:
                return m_fontSize;
            case TextProperty:
                return m_text;
            case TextColorProperty:
                return m_textColor;
            default:
                return Item::property(id);
        }
    }

    void LabelItem::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            case FontFamilyProperty:
                m_fontFamily = value.toString();
                break;
            case FontSizeProperty:
                m_fontSize = value.toInt();
                break;
            case TextProperty:
                m_text = value.toString();
                break;
            case TextColorProperty:
                m_textColor = value.toString();
                break;
            default:
                Item::setProperty(id, value);
                break;
        }
    }

    QList<PropertyId> LabelItem::propertyIdList() const
    {
        return Item::propertyIdList()
                << VerticesProperty;
    }

    PinItem::PinItem():
        Item()
    {

    }

    PinItem::~PinItem()
    {
        delete(designator);
        delete(label);
    }

    ItemType PinItem::type() const
    {
        return Pin;
    }

    // FIXME: have to deep clone
    Item *PinItem::clone() const
    {
        auto item = new PinItem;
        *item = *this;
        return item;
    }

    QPainterPath PinItem::outline() const
    {
        return QPainterPath(); // FIXME: need pin length
    }

    QString PinItem::friendlyTypeName() const
    {
        return "Pin";
    }

    QString PinItem::friendlyPropertyName(quint64 id) const
    {
        switch (id)
        {
            default:
                return Item::friendlyPropertyName(id);
        }
    }

    QIcon PinItem::icon() const
    {
        return QIcon::fromTheme("network-connect");
    }

    QVariant PinItem::property(quint64 id) const
    {
        switch (id)
        {
            default:
                return Item::property(id);
        }
    }

    void PinItem::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            default:
                Item::setProperty(id, value);
                break;
        }
    }

    QList<PropertyId> PinItem::propertyIdList() const
    {
        return Item::propertyIdList();
    }

    ItemGroup::ItemGroup():
        Item()
    {

    }

    ItemGroup::~ItemGroup()
    {
        qDeleteAll(children);
    }

    ItemType ItemGroup::type() const
    {
        return Group;
    }

    // FIXME: have to deep clone
    Item *ItemGroup::clone() const
    {
        auto item = new ItemGroup;
        *item = *this;
        return item;
    }

    QPainterPath ItemGroup::outline() const
    {
        return QPainterPath(); // FIXME: need access to item in group
    }

    QString ItemGroup::friendlyTypeName() const
    {
        return "Group";
    }

    QString ItemGroup::friendlyPropertyName(quint64 id) const
    {
        switch (id)
        {
            default:
                return Item::friendlyPropertyName(id);
        }
    }

    QIcon ItemGroup::icon() const
    {
        return QIcon::fromTheme("object-group");
    }

    QVariant ItemGroup::property(quint64 id) const
    {
        switch (id)
        {
            default:
                return Item::property(id);
        }
    }

    void ItemGroup::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            default:
                Item::setProperty(id, value);
                break;
        }
    }

    QList<PropertyId> ItemGroup::propertyIdList() const
    {
        return Item::propertyIdList();
    }

    void registerMetaTypes()
    {
        qRegisterMetaType<LineStyle>();
        qRegisterMetaType<LineWidth>();
        qRegisterMetaType<FillStyle>();
        qRegisterMetaType<Color>();
    }

}
